Skip to content

Support boolean values for --self-contained flag#52333

Open
Copilot wants to merge 13 commits intorelease/10.0.3xxfrom
copilot/support-self-contained-boolean
Open

Support boolean values for --self-contained flag#52333
Copilot wants to merge 13 commits intorelease/10.0.3xxfrom
copilot/support-self-contained-boolean

Conversation

Copy link
Contributor

Copilot AI commented Jan 6, 2026

Plan: Support boolean values for --self-contained flag

Analysis

The issue is that customers pass --self-contained true/false but the CLI currently ignores the false value. The ForwardIfEnabled method only forwards when the boolean is true.

Changes Required

  • Explore codebase and understand current implementation
  • Modify SelfContainedOption in CommonOptions.cs to use ForwardAsMany instead of ForwardIfEnabled to support both true and false values
  • Test manually with dogfood environment - verified all scenarios work
  • Merge origin/release/10.0.3xx and resolve conflicts
  • Apply @baronfel's feedback to use bool instead of bool?
  • Fix CS9174 compilation error in ForwardedOptionExtensions.cs
  • Ensure boolean values are lowercase for MSBuild compatibility
  • Run existing tests to ensure no regressions
  • Run code review
  • Run security scan

Implementation Details

  1. ✅ Changed SelfContainedOption to forward both true and false values using ForwardAsMany
  2. ✅ Kept NoSelfContainedOption for backward compatibility with --no-self-contained
  3. ✅ Validation correctly detects conflicts between --self-contained and --no-self-contained options
  4. ✅ Manual testing verified:
    • --self-contained=false → framework-dependent (5 files)
    • --self-contained=true → self-contained (192 files)
    • --self-contained (no value) → self-contained (192 files)
    • --self-contained=true --no-self-contained → error (as expected)
  5. ✅ Merged origin/release/10.0.3xx and resolved conflicts (commit a8e061b)
  6. ✅ Applied @baronfel's feedback: Changed from bool? to bool to simplify implementation (commit f1a9e82)
    • System.CommandLine always provides a value for bool options, so nullable is unnecessary
    • Removed HasValue check and directly use the bool value
    • Reverted type changes in RunCommandDefinition, BuildCommandDefinition, and PublishCommandDefinition
  7. ✅ Fixed CS9174 compilation error: IfExplicitlyProvided() method was returning [] instead of option (commit 6ed90e0)
  8. ✅ Ensured boolean values are lowercase ("true"/"false") for MSBuild compatibility using ternary operator pattern (commit pending)
Original prompt

A lot of customers assume that --self-contained is a boolean and they pass true and false to it but today we ignore that boolean. Rather than remove this flag and break people, let's actually support the boolean for this flag. Please make it so that true sets self-contained as it does today but make --self-contained false disable self-contained.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Co-authored-by: marcpopMSFT <12663534+marcpopMSFT@users.noreply.github.com>
@marcpopMSFT
Copy link
Member

I tested and it works correctly and the code looks right. There are a surprising number of tests that were dependent on this not working which is confusing.

@marcpopMSFT marcpopMSFT marked this pull request as ready for review January 9, 2026 00:45
@marcpopMSFT marcpopMSFT requested a review from baronfel January 9, 2026 00:45
@marcpopMSFT
Copy link
Member

I tested all four possible options:

  1. nothing specified
  2. --self-contained
  3. --self-contained false
  4. --self-contained true

We will set _CommandLineDefinedSelfContained when false now though that seems correct (and we don't appear to use it anywhere). _SelfContainedWasSpecified will now also be true when setting false.

@marcpopMSFT
Copy link
Member

note that before, --self-contained false was a weird grey area as it wouldn't set self-contained (so we were actually taking into account the boolean). This is because ForwardIfEnabled would only set self contained if the value were true (or empty). If false, it wouldn't forward the command from what I can tell. That means it's not as bad as I had assumed but it does mean if you have SelfContained specified elsewhere, the CLI false value won't affect it.

@marcpopMSFT marcpopMSFT changed the base branch from release/10.0.2xx to release/10.0.3xx January 16, 2026 18:30
@mmitche mmitche deleted the branch release/10.0.3xx January 17, 2026 00:40
@mmitche mmitche closed this Jan 17, 2026
@marcpopMSFT marcpopMSFT reopened this Jan 20, 2026
@marcpopMSFT
Copy link
Member

@copilot there are merge conflicts with origin/release/10.0.3xx, can you please merge that in and fix the conflicts?

…upport-self-contained-boolean

# Conflicts:
#	src/Cli/Microsoft.DotNet.Cli.Definitions/Common/CommonOptions.cs
Copy link
Contributor Author

Copilot AI commented Jan 26, 2026

@copilot there are merge conflicts with origin/release/10.0.3xx, can you please merge that in and fix the conflicts?

Merged origin/release/10.0.3xx and resolved the conflict in CommonOptions.cs (commit a8e061b).

@marcpopMSFT
Copy link
Member

marcpopMSFT commented Jan 26, 2026

@baronfel review at your leisure. Not as bad as I originally thought but probably still worth taking.

@marcpopMSFT marcpopMSFT changed the title [WIP] Support boolean values for --self-contained flag Support boolean values for --self-contained flag Jan 26, 2026
Copy link
Member

@baronfel baronfel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot can you apply my feedback please?

Arity = ArgumentArity.ZeroOrOne
}
.ForwardIfEnabled([$"--property:SelfContained=true", "--property:_CommandLineDefinedSelfContained=true"]);
.ForwardAsMany(o => o.HasValue ? [$"--property:SelfContained={o.Value}", "--property:_CommandLineDefinedSelfContained=true"] : []);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC nullable bool isn't quite the correct thing here - S.CL defaults will always provide a value for the bool, so HasValue will always be true. Here's a quick test bed I wrote:

> dotnet run .\scl.cs                                                                                                           
Command: foo -o
  Has option: True
  Option value: True
  Value type: explicit

Command: foo -o true
  Has option: True
  Option value: True
  Value type: explicit

Command: foo -o false
  Has option: True
  Option value: False
  Value type: explicit

Not using the nullable means that the changes to most of the other files don't have to happen.

Co-authored-by: baronfel <573979+baronfel@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jan 26, 2026

@copilot can you apply my feedback please?

Applied your feedback in commit f1a9e82. Changed from bool? to bool and removed the HasValue check, simplifying the implementation as you suggested.

@marcpopMSFT
Copy link
Member

Retested and I can confirm that we get SelfContained false if not specified (and the other two _ are empty). If I set any self-contained CLI option, the other two _ options are true and SelfContained matches the boolean.

@baronfel one weirdness is that SelfContained will be capitalized with this solution if set. Should we fix that to make sure it's lowercase always?

@marcpopMSFT
Copy link
Member

fwiw, I also confirmed that --self-contained false will override a SelfContained=true in a project file. That seems like expected behavior for the CLI to override the project file though.

@marcpopMSFT
Copy link
Member

Hmm, tests are failing because SelfContained is set where it wasn't before. I'll have to dig into those tests.

@marcpopMSFT
Copy link
Member

@copilot
src/Cli/Microsoft.DotNet.Cli.CommandLine/ForwardedOptionExtensions.cs(164,20): error CS9174: (NETCORE_ENGINEERING_TELEMETRY=Build) Cannot initialize type 'Option' with a collection expression because the type is not constructible

Co-authored-by: marcpopMSFT <12663534+marcpopMSFT@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 6, 2026

@copilot
src/Cli/Microsoft.DotNet.Cli.CommandLine/ForwardedOptionExtensions.cs(164,20): error CS9174: (NETCORE_ENGINEERING_TELEMETRY=Build) Cannot initialize type 'Option' with a collection ...

Fixed in commit 6ed90e0. The IfExplicitlyProvided() method was incorrectly returning an empty collection [] instead of returning option. The method signature is Option<TValue> IfExplicitlyProvided(), so it should return the option itself to enable method chaining.

@marcpopMSFT
Copy link
Member

@copilot Can you ensure that when we set SelfContained, that the boolean value is lowercase as that's what msbuild expects?

Co-authored-by: marcpopMSFT <12663534+marcpopMSFT@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 6, 2026

@copilot Can you ensure that when we set SelfContained, that the boolean value is lowercase as that's what msbuild expects?

Fixed in commit 91ddbe4. Changed the implementation to use a ternary operator (o ? "true" : "false") to ensure the boolean value is always lowercase, matching the pattern used in other options like CreateInteractiveMsBuildForwardOption(). Verified that MSBuild now receives --property:SelfContained=true and --property:SelfContained=false with lowercase values.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants